package io.github.iogogogo.redis.configuration;

import io.github.iogogogo.redis.properties.RedisInstanceProperties;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.HashSet;
import java.util.Objects;

/**
 * Created by tao.zeng on 2024/11/18.
 */
@Slf4j
@org.springframework.context.annotation.Configuration
@ConditionalOnProperty(prefix = "spring.data.redis.biz-commons", value = "enable", havingValue = "true")
public class RedisAutoConfiguration {

    @Resource
    private RedisInstanceProperties bizRedisProperties;

    @Resource
    private RedisProperties redisProperties;

    // @Bean
    public MultipleRedisConfiguration multiInstanceConfigure(Environment environment) {
        Binder binder = Binder.get(environment);
        RedisInstanceProperties properties = binder.bind(RedisInstanceProperties.CONF_PREFIX, RedisInstanceProperties.class).get();
        MultipleRedisConfiguration configuration = new MultipleRedisConfiguration();
        configuration.setRedisInstanceProperties(properties);
        return configuration;
    }

    @Bean
    @Qualifier("bizCommonsRedisConnectionFactory")
    public RedisConnectionFactory bizCommonsRedisConnectionFactory() {
        return getRedisConnectionFactory(bizRedisProperties.getBizCommons());
    }

    private RedisConnectionFactory getRedisConnectionFactory(RedisProperties redisProperties) {
        RedisProperties.Cluster cluster = redisProperties.getCluster();
        RedisProperties.Sentinel sentinel = redisProperties.getSentinel();

        RedisConnectionFactory connectionFactory;
        if (Objects.nonNull(cluster) && CollectionUtils.isNotEmpty(cluster.getNodes())) {
            connectionFactory = clusterRedisConnectionFactory(redisProperties);
        } else if (Objects.nonNull(sentinel) && CollectionUtils.isNotEmpty(sentinel.getNodes())) {
            connectionFactory = sentinelRedisConnectionFactory(redisProperties);
        } else {
            connectionFactory = standaloneRedisConnectionFactory(redisProperties);
        }
        return connectionFactory;
    }

    @Bean
    @Qualifier("bizCommonsStringRedisTemplate")
    public RedisTemplate<?, ?> bizCommonsStringRedisTemplate(@Qualifier("bizCommonsRedisConnectionFactory") RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }

    private RedisConnectionFactory standaloneRedisConnectionFactory(RedisProperties redisProperties) {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort());
        configuration.setUsername(redisProperties.getUsername());
        configuration.setPassword(redisProperties.getPassword());
        configuration.setDatabase(redisProperties.getDatabase());
        return new LettuceConnectionFactory(configuration);
    }

    private RedisConnectionFactory clusterRedisConnectionFactory(RedisProperties redisProperties) {
        RedisProperties.Cluster cluster = redisProperties.getCluster();
        RedisClusterConfiguration configuration = new RedisClusterConfiguration(cluster.getNodes());
        configuration.setUsername(redisProperties.getUsername());
        configuration.setPassword(redisProperties.getPassword());
        configuration.setMaxRedirects(cluster.getMaxRedirects());
        return new LettuceConnectionFactory(configuration);
    }

    private RedisConnectionFactory sentinelRedisConnectionFactory(RedisProperties redisProperties) {
        RedisProperties.Sentinel sentinel = redisProperties.getSentinel();
        RedisSentinelConfiguration configuration = new RedisSentinelConfiguration(sentinel.getMaster(), new HashSet<>(sentinel.getNodes()));
        configuration.setPassword(redisProperties.getPassword());
        configuration.setUsername(redisProperties.getUsername());
        configuration.setDatabase(redisProperties.getDatabase());
        return new LettuceConnectionFactory(configuration);
    }
}
